home *** CD-ROM | disk | FTP | other *** search
/ Atari Forever 4 / Atari Forever 4.zip / Atari Forever 4.iso / SERIE_AI / AI_029 / RDXFS_R1.LZH / archive.lzh / ramdisk / ramutil.c < prev    next >
C/C++ Source or Header  |  1996-04-23  |  50KB  |  1,787 lines

  1. /*
  2.  * ramutil.c vom 23.04.1996
  3.  *
  4.  * Autor:
  5.  * Thomas Binder
  6.  * (binder@rbg.informatik.th-darmstadt.de)
  7.  *
  8.  * Zweck:
  9.  * Enthält die Hilfsroutinen des Ramdisk-XFS für MagiC (also solche,
  10.  * die nicht direkt von der XFS-Schnittstelle angesprungen werden).
  11.  *
  12.  * History:
  13.  * 30.12.1995: Erstellung.
  14.  *             In work_entry wird das x-Flag jetzt nicht mehr geprüft,
  15.  *             in findfile nur noch dann, wenn nicht das Verzeichnis
  16.  *             selbst gesucht ist.
  17.  * 31.12.1995: Neue Funktion "increase_refcnts", näheres in ramdisk.c
  18.  * 01.01.1996: Wird work_entry NULL für action übergeben, liefert es
  19.  *             EINVFN sobald der Test auf einen symbolischen Link
  20.  *             nicht erfolgreich war.
  21.  * 02.01.1996: In prepare_dir wird jetzt für die Blockgröße des
  22.  *             Wurzelverzeichnisses eine Null eingetragen.
  23.  * 03.01.1996: get_and_set_drive sucht jetzt bis Laufwerk Z.
  24.  * 20.01.1996: Sämliche static-chars innerhalb von Funktionen durch
  25.  *             per int_malloc angeforderte ersetzt. Damit ist die
  26.  *             Ramdisk jetzt voll reentrant.
  27.  * 05.02.1996: findfile sucht im Modus FF_EXIST nur noch dann mit
  28.  *             TOS-gestutzten bzw. caseinsensitiven Filenamen weiter,
  29.  *             wenn die TOS-Domain aktiv ist.
  30.  * 10.02.-
  31.  * 12.02.1996: Weiterführung der Kommentierung.
  32.  * 12.02.1996: Kmalloc prüft jetzt, ob der größte Speicherblock minus
  33.  *             der gewünschten Anzahl Bytes noch groß genug ist
  34.  *             (bisher fehlte das Minus...)
  35.  * 13.02.1996: Anpassung an den neuen Prototyp von install_xfs (siehe
  36.  *             pc_xfs.h)
  37.  * 14.02.1996: Auswertung der Infodatei begonnen.
  38.  * 16.02.1996: Auswertung fertiggestellt.
  39.  * 17.02.1996: Neues Kommando für die Infodatei: 8bit, legt fest, ob
  40.  *             in Filenamen ASCII-Zeichen > 127 erlaubt sind. Dafür
  41.  *             mußte natürlich auch check_name angepaßt werden.
  42.  *             Die Debug-Version unterstützt jetzt zusätzlich die
  43.  *             Kommandos logfile und logbackup in der Infodatei.
  44.  *             findfile nochmal überarbeitet.
  45.  * 19.02.1996: Kmalloc verbessert: Erst wird versucht, einen Block
  46.  *             der gewünschten Größe anzufordern. Klappt das nicht,
  47.  *             ist Schluß. Ansonsten wird jetzt geprüft, ob sich die
  48.  *             Lange des größten noch freien Speicherblocks geändert
  49.  *             hat. Falls nicht, wird der Block so als Ergebnis
  50.  *             geliefert. Im anderen Fall wird der Block wieder
  51.  *             freigegeben, wenn der neue Wert kleiner als der
  52.  *             Mindestwert ist. Auf diese Weise kann die Ramdisk auch
  53.  *             bei stark fragmentiertem Speicher noch neue Daten
  54.  *             aufnehmen.
  55.  * 26.02.1996: Die Funktion readline stark beschleunigt, außerdem
  56.  *             wird jetzt kein Linefeed bei der letzten Zeile mehr
  57.  *             benötigt.
  58.  *             Neues Kommando für die INF-Datei: label, zum Festlegen
  59.  *             des Volume Labels.
  60.  *             Einschaltmeldung korrigiert.
  61.  * 23.04.1996: Beim Start wird jetzt erstmal der MagX-Cookie geprüft.
  62.  */
  63.  
  64. #include <string.h>
  65. #include <stdlib.h>
  66. #include <ctype.h>
  67. /*
  68.  * Ein XFS kann man schlecht bis überhaupt nicht mit konventionellen
  69.  * Mitteln (sprich: Pure Debugger) debuggen, daher verwende ich
  70.  * ganz einfach an den wichtigsten Stellen Debugausgaben, mit deren
  71.  * Hilfe man Fehler schnell einkreisen kann. Selbstverständlich
  72.  * sind diese im tatsächlichen Betrieb störend, daher werden sie nur
  73.  * eincompiliert, wenn DEBUG definiert ist. LOGFILE legt dabei fest,
  74.  * in welches File die Ausgaben geschrieben werden sollen, LOGBACK
  75.  * ist das Backupfile (bei jedem Start wird das alte Backupfile
  76.  * gelöscht, das letzte Debugfile in LOGBACK umbenannt und ein neues
  77.  * Logfile begonnen). Hier kann man auch u:\\dev\\prn verwenden, wenn
  78.  * man zuviel Papier hat ;)
  79.  * LOGFILE und LOGBACK müssen absolute Pfade mit Laufwerkskennung
  80.  * sein und auf dem gleichen physikalischen Laufwerk liegen.
  81.  * Wird beim Start eine der Umschalttasten festgehalten, wird direkt
  82.  * auf die Console (also normalerweise auf den Bildschirm)
  83.  * ausgegeben. Den gleichen Effekt erhält man durch u:\\dev\\con
  84.  * für LOGFILE. LOGBACK sollte dann weggelassen werden.
  85.  * Selbstverständlich wird das Filesystem durch die Debug-Ausgaben
  86.  * sehr stark gebremst, vor allem, wenn man sie in eine Datei auf
  87.  * der Festplatte ausgeben läßt. Wer's ganz trickreich machen will,
  88.  * legt das Logfile der Ramdisk auf eine andere(!) Ramdisk, damit ist
  89.  * die Geschwindigkeit einigermaßen erträglich.
  90.  * Ach ja, das Ganze ist nur der Default, da man in der Infodatei
  91.  * auch andere Dateien festlegen kann.
  92.  * Das Logfile wird übrigens recht schnell sehr groß, daher sollte
  93.  * man es ab und an löschen, wenn keine Fehler aufgetreten sind. Das
  94.  * Löschen schadet nichts, da die Datei nur direkt für Ausgaben
  95.  * geöffnet wird.
  96.  */
  97. #ifdef DEBUG
  98. #define LOGFILE    "c:\\gemsys\\magic\\xtension\\ramdebug.log"
  99. #define LOGBACK    "c:\\gemsys\\magic\\xtension\\ramdebug.olg"
  100. #include <stdarg.h>
  101. #endif /* DEBUG */
  102. #define ONLY_EXTERN
  103. #include "ramdisk.h"
  104.  
  105. static WORD    wait_for_key;
  106. static char    mountname[256];
  107. #ifdef DEBUG
  108. static char    logfile[256];
  109. static char logback[256];
  110. #endif
  111.  
  112. WORD main(void)
  113. {
  114.     char    help[2];
  115.  
  116. /* MagX-Cookie suchen und abbrechen, wenn nicht vorhanden */
  117.     if (!get_cookie('MagX', NULL))
  118.     {
  119.         Cconws("The Ramdisk-XFS only works with MagiC 3 or better!"
  120.             "\r\n");
  121.         Cconws("Please press any key!\r\n");
  122.         Cnecin();
  123.         return(-1);
  124.     }
  125.     Cconws("\r\nRamdisk-XFS dated "VERSION"\r\n");
  126.     Cconws("(c) 1995-1996 by Thomas Binder\r\n");
  127. /* Die Parameter mit Defaultwerten belegen */
  128.     leave_free = LEAVE_FREE;
  129.     ram_type = RAM_TYPE;
  130.     ramdisk_drive = -1;
  131.     strcpy(mountname, "");
  132.     strcpy(volume_label, "");
  133.     eight_bit = 0;
  134. #ifdef DEBUG
  135.     strcpy(logfile, LOGFILE);
  136. #ifdef LOGBACK
  137.     strcpy(logback, "");
  138. #else
  139.     strcpy(logback, LOGBACK);
  140. #endif /* LOGBACK */
  141. #endif /* DEBUG */
  142.     read_infofile();
  143. /*
  144.  * Zunächst ein/das Laufwerk für die Ramdisk ermitteln. Leider bietet
  145.  * MagiC nicht die Möglichkeit, ein Filesystem direkt zu mounten; man
  146.  * man muß also immer mindestens ein BIOS-Laufwerk belegen, ob man es
  147.  * nun braucht, oder nicht.
  148.  */
  149.     if (ramdisk_drive < 0)
  150.     {
  151.         if ((ramdisk_drive = (WORD)Supexec(get_and_set_drive)) == -1)
  152.         {
  153.             Cconws("Installation failed (no free drive)!r\n");
  154.             Cconws("Please press any key!\r\n");
  155.             Cnecin();
  156.             return(-1);
  157.         }
  158.     }
  159.     else
  160.     {
  161.         if (Supexec(set_ramdisk_drive) == 0L)
  162.         {
  163.             Cconws("Installation failed (drive already in use)!"
  164.                 "\r\n");
  165.             Cconws("Please press any key!\r\n");
  166.             Cnecin();
  167.             return(-1);
  168.         }
  169.     }
  170. /*
  171.  * Die Kernelstruktur ermitteln und prüfen, ob die per int_malloc
  172.  * angeforderten Speicherstücke groß genug sind, um einen temporären
  173.  * Filenamen der Ramdisk aufzunehmen.
  174.  */
  175.     if ((kernel = (THE_MX_KERNEL *)Dcntl(KER_GETINFO, NULL, NULL)) ==
  176.         NULL)
  177.     {
  178.         Cconws("Installation failed (kernel structure unavailable)!"
  179.             "\r\n");
  180.         Cconws("Please press any key!\r\n");
  181.         Cnecin();
  182.         return(-1);
  183.     }
  184.     if (kernel->int_msize < 34)
  185.     {
  186.         Cconws("Installation failed (kernel blocksize too small)!"
  187.             "\r\n");
  188.         Cconws("Please press any key!\r\n");
  189.         Cnecin();
  190.         return(-1);
  191.     }
  192. /*
  193.  * Jetzt das XFS mit der Funktion install_xfs aus pc_xfs.h beim
  194.  * Kernel anmelden. Zurückgeliefert wird der Zeiger auf die
  195.  * angepaßte Kernelstruktur, die man für Funktionsaufrufe benutzen
  196.  * muß. Die tatsächliche Struktur (wie sie schon weiter oben per
  197.  * Dcntl ermittelt wurde) findet sich jetzt im Zeiger real_kernel.
  198.  */
  199.     if ((kernel = install_xfs(&ramdisk_xfs)) == NULL)
  200.     {
  201.         Cconws("Installation failed!\r\n");
  202.         Cconws("Please press any key!\r\n");
  203.         Cnecin();
  204.         return(-1);
  205.     }
  206. /*
  207.  * Die Ramdisk ist jetzt beim Kernel angemeldet und kann danach nicht
  208.  * mehr entfehrnt werden. Sollte also bei dem Versuch, den Namen in
  209.  * U:\ zu ändern, etwas schiefgehen, muß der Benutzer damit leben.
  210.  */
  211.     help[0] = ramdisk_drive + 65;
  212.     help[1] = 0;
  213.     Cconws("Installed as U:\\");
  214.     if (*mountname)
  215.     {
  216.         Dsetdrv('U' - 'A');
  217.         Dsetpath("\\");
  218.         help[0] = ramdisk_drive + 65;
  219.         help[1] = 0;
  220.         if (Frename(0, help, mountname) != 0L)
  221.         {
  222.             Cconws(help);
  223.             Cconws("! (Frename failed)\r\n");
  224.             wait_for_key = 1;
  225.         }
  226.         else
  227.         {
  228.             Cconws(mountname);
  229.             Cconws("!\r\n");
  230.         }
  231.     }
  232.     else
  233.     {
  234.         Cconout(65 + ramdisk_drive);
  235.         Cconws("!\r\n");
  236.     }
  237. #ifdef DEBUG
  238.     Cconws("MagiC-Kernelversion ");
  239.     Cconout(48 + real_kernel->version);
  240.     Cconws("\r\nDebug-output to ");
  241.     if (Kbshift(-1) & 31)
  242.     {
  243.         debug_to_screen = 1;
  244.         Cconws("screen\r\n");
  245.     }
  246.     else
  247.     {
  248.         if (*logback)
  249.         {
  250.             Fdelete(logback);
  251.             Frename(0, logfile, logback);
  252.         }
  253.         debug_to_screen = 0;
  254.         Cconws(logfile);
  255.         Cconws("\r\n");
  256.     }
  257. #endif
  258. /* Startzeit und -datum für das Wurzelverzeichnis merken */
  259.     starttime = Tgettime();
  260.     startdate = Tgetdate();
  261.     if (wait_for_key)
  262.     {
  263.         Cconws("Please press any key!\r\n");
  264.         Cnecin();
  265.     }
  266. /*
  267.  * Ein XFS muß, sobald es erfolgreich mit install_xfs angemeldet
  268.  * wurde, dauerhaft im Speicher verbleiben, deswegen muß hier
  269.  * Ptermres aufgerufen werden. Das nachfolgende return ist eigentlich
  270.  * sinnlos, hält Pure C aber vom Meckern ab...
  271.  */
  272.     Ptermres(_PgmSize, 0);
  273.     return(0);
  274. }
  275.  
  276. /*
  277.  * read_infofile
  278.  *
  279.  * Liest die INF-Datei des Ramdisk-XFS und wertet sie aus. Ungültige
  280.  * Zeilen werden gemeldet und nicht beachtet.
  281.  */
  282. void read_infofile(void)
  283. {
  284.     static char    filename[128],
  285.                 input[256];
  286.     char        *prgname,
  287.                 *filename2,
  288.                 *arg,
  289.                 *pos;
  290.     LONG        err;
  291.     WORD        handle;
  292.  
  293.     wait_for_key = 0;
  294. /*
  295.  * Die Datei findet sich entweder im Ordner \gemsys\magic\xtension
  296.  * des aktuellen Laufwerks, in dessen Wurzelverzeichnis oder im
  297.  * aktuellen Verzeichnis
  298.  */
  299.     strcpy(filename, "\\gemsys\\magic\\xtension\\");
  300.     filename2 = strrchr(filename, '\\');
  301. /*
  302.  * Versuchen, den Namen des Filesystems über den von MagiC angelegte
  303.  * Environment-Variable _PNAM zu ermittlen. Geht das nicht, wird der
  304.  * Name der INF-Datei auf ramdisk.inf gesetzt und direkt zum Öffnen
  305.  * der Datei verzweigt (per unbeliebtem goto...)
  306.  */
  307.     if ((prgname = getenv("_PNAM")) == NULL)
  308.     {
  309.         strcat(filename, "ramdisk.inf");
  310.         goto open_file;
  311.     }
  312. /*
  313.  * Enthält der Programmname keinen Punkt, wird direkt .inf angehängt
  314.  * und zum Fileöffnen verzweigt (schon wieder goto...)
  315.  */
  316.     if ((pos = strrchr(prgname, '.')) == NULL)
  317.     {
  318.         if (*prgname == '\\')
  319.         {
  320.             strcpy(filename, prgname);
  321.             filename2 = NULL;
  322.         }
  323.         else
  324.             strcat(filename, prgname);
  325.         strcat(filename, ".inf");
  326.         goto open_file;
  327.     }
  328. /* Ansonsten wird die Extension durch ".inf" ersetzt */
  329.     *pos = 0;
  330.     if (*prgname == '\\')
  331.     {
  332.         filename2 = NULL;
  333.         strcpy(filename, prgname);
  334.     }
  335.     else
  336.         strcat(filename, prgname);
  337.     *pos = '.';
  338.     strcat(filename, ".inf");
  339. /*
  340.  * Die Datei öffnen; wenn der Programmname ein absoluter Pfad war,
  341.  * wird nur dort gesucht, sonst auch im Wurzelverzeichnis und im
  342.  * aktuellen Verzeichnis
  343.  */
  344. open_file:
  345.     if (((err = Fopen(filename, FO_READ)) < 0L) && (!filename2 ||
  346.         (((err = Fopen(filename2, FO_READ)) < 0L) &&
  347.         ((err = Fopen(++filename2, FO_READ)) < 0L))))
  348.     {
  349.         return;
  350.     }
  351.     handle = (WORD)err;
  352. /* Die Datei zeilenweise auslesen und auswerten */
  353.     while (readline(handle, input))
  354.     {
  355. /* Leerzeilen werden komplett ignoriert */
  356.         if (!*input)
  357.             continue;
  358. /* Jede Zeile muß mindestens ein Gleichheitszeichen enthalten */
  359.         if ((arg = strchr(input, '=')) == NULL)
  360.         {
  361. /*
  362.  * Ungültige Zeilen werden gemeldet und übergangen; außerdem wird
  363.  * ein Flag gesetzt, damit vor Programmende auf einen Tastendruck
  364.  * gewartet wird (sonst sind die Meldungen u.U. zu schnell wieder
  365.  * weg)
  366.  */
  367. invalid_line:
  368.             if (arg != NULL)
  369.                 *arg = '=';
  370.             Cconws("Invalid line in INF-file (ignored):\r\n");
  371.             Cconws(input);
  372.             Cconws("\r\n");
  373.             wait_for_key = 1;
  374.             continue;
  375.         }
  376.         *arg = 0;
  377. /*
  378.  * Folgt hinter dem Gleichheitszeichen nichts mehr, ist die Zeile
  379.  * ungültig
  380.  */
  381.         if (!arg[1])
  382.             goto invalid_line;
  383. /*
  384.  * Hinter dem Kommando drive= muß ein Laufwerksbuchstabe zwischen
  385.  * 'A' und 'Z' (jeweils einschließlich) außer 'U' folgen, sonst ist
  386.  * die Zeile falsch
  387.  */
  388.         if (!stricmp(input, "drive"))
  389.         {
  390.             if (arg[2])
  391.                 goto invalid_line;
  392.             arg[1] &= ~32;
  393.             if ((arg[1] < 'A') || (arg[1] > 'Z') || (arg[1] == 'U'))
  394.                 goto invalid_line;
  395.             ramdisk_drive = arg[1] - 'A';
  396.             continue;
  397.         }
  398. /*
  399.  * Der Text hinter mountname= wird ohne weitere Prüfungen übernommen
  400.  */
  401.         if (!stricmp(input, "mountname"))
  402.         {
  403.             strcpy(mountname, &arg[1]);
  404.             continue;
  405.         }
  406. /*
  407.  * Hinter ramtype= dürfen stonly, altonly, storalt oder altorst
  408.  * folgen, alles andere macht die Zeile ungültig
  409.  */
  410.         if (!stricmp(input, "ramtype"))
  411.         {
  412.             if (!stricmp(&arg[1], "stonly"))
  413.                 ram_type = 0;
  414.             else if (!stricmp(&arg[1], "altonly"))
  415.                 ram_type = 1;
  416.             else if (!stricmp(&arg[1], "storalt"))
  417.                 ram_type = 2;
  418.             else if (!stricmp(&arg[1], "altorst"))
  419.                 ram_type = 3;
  420.             else
  421.                 goto invalid_line;
  422.             continue;
  423.         }
  424. /*
  425.  * Der Inhalt der Zeile hinter leavefree= wird in eine Zahl gewandelt
  426.  * und mit 1024 multipliziert. Weitere Überprüfungen finden nicht
  427.  * statt.
  428.  */
  429.         if (!stricmp(input, "leavefree"))
  430.         {
  431.             leave_free = atol(&arg[1]) * 1024L;
  432.             continue;
  433.         }
  434. /* Hinter 8bit= muß entweder "true" oder "false" folgen */
  435.         if (!stricmp(input, "8bit"))
  436.         {
  437.             if (!stricmp(&arg[1], "true"))
  438.                 eight_bit = 1;
  439.             else if (!stricmp(&arg[1], "false"))
  440.                 eight_bit = 0;
  441.             else
  442.                 goto invalid_line;
  443.             continue;
  444.         }
  445. /* Die ersten 32 Zeichen hinter label= werden direkt übernommen */
  446.         if (!stricmp(input, "label"))
  447.         {
  448.             volume_label[32] = 0;
  449.             strncpy(volume_label, &arg[1], 32L);
  450.             continue;
  451.         }
  452. #ifdef DEBUG
  453.         if (!stricmp(input, "logfile"))
  454.         {
  455.             strcpy(logfile, &arg[1]);
  456.             strcpy(logback, "");
  457.             continue;
  458.         }
  459.         if (!stricmp(input, "logbackup"))
  460.         {
  461.             strcpy(logback, &arg[1]);
  462.             continue;
  463.         }
  464. #endif
  465. /*
  466.  * Sollte die Zeile nicht mit drive, mountname, ramtype, leavefree
  467.  * oder 8bit begonnen haben, ist sie ebenfalls ungültig
  468.  */
  469.         goto invalid_line;
  470.     }
  471.     Fclose(handle);
  472. }
  473.  
  474. /*
  475.  * readline
  476.  *
  477.  * Liest eine Zeile aus einer GEMDOS-Datei ein,
  478.  * die wahlweise mit CRLF oder nur LF enden darf.
  479.  * Beginnt sie mit einem '#', wird gleich die
  480.  * nächste Zeile eingelesen.
  481.  *
  482.  * Eingabe:
  483.  * handle: Zu benutzendes GEMDOS-Handle
  484.  * buffer: Zeiger auf 255 Byte großen Zeilenpuffer
  485.  *
  486.  * Rückgabe:
  487.  * 0: Fehler beim Lesen (oder: Zeile zu lang)
  488.  * 1: Alles OK
  489.  */
  490. WORD readline(WORD handle, char *buffer)
  491. {
  492.     WORD    count;
  493.     LONG    fpos,
  494.             add,
  495.             bytes_read;
  496.  
  497.     for (;;)
  498.     {
  499.         fpos = Fseek(0L, handle, 1);
  500.         if (fpos < 0L)
  501.             return(0);
  502.         if ((bytes_read = Fread(handle, 255, buffer)) <= 0L)
  503.         {
  504.             return(0);
  505.         }
  506.         count = 0;
  507.         add = 1L;
  508.         for (;;)
  509.         {
  510.             if (count == bytes_read)
  511.             {
  512.                 add = 0L;
  513.                 break;
  514.             }
  515.             if (buffer[count] == '\n')
  516.                 break;
  517.             if (count == 255)
  518.                 return(0);
  519.             if (buffer[count] == '\t')
  520.                 buffer[count] = ' ';
  521.             count++;
  522.         }
  523.         if (Fseek((LONG)count + fpos + add, handle, 0) < 0L)
  524.         {
  525.             return(0);
  526.         }
  527.         if (count)
  528.         {
  529.             if (buffer[count - 1] == '\r')
  530.                 count--;
  531.         }
  532.         buffer[count] = 0;
  533.         if (*buffer != '#')
  534.             break;
  535.     }
  536.     return(1);
  537. }
  538.  
  539. /*
  540.  * get_and_set_drive
  541.  *
  542.  * Parameterfunktion für Supexec, die ein freies Laufwerk in _drvbits
  543.  * sucht und belegt. Von der Suche ausgenommen sind A, B und U.
  544.  *
  545.  * Rückgabe:
  546.  * -1: Keine freie Laufwerkskennung mehr vorhanden.
  547.  * sonst: Belegte Laufwerksnummer (2 = C, 3 = D, etc.)
  548.  */
  549. LONG get_and_set_drive(void)
  550. {
  551.     LONG    *_drvbits,
  552.             i;
  553.  
  554.     _drvbits = (LONG *)0x4c2;
  555.     for (i = 2L; i < 26L; i++)
  556.     {
  557.         if ((i != (LONG)('U' - 'A')) && !(*_drvbits & (1L << i)))
  558.         {
  559.             *_drvbits |= (1L << i);
  560.             break;
  561.         }
  562.     }
  563.     if (i == 26L)
  564.         return(-1L);
  565.     else
  566.         return(i);
  567. }
  568.  
  569. /*
  570.  * set_ramdisk_drive
  571.  *
  572.  * Ähnlich wie get_and_set_drive, versucht aber nur, das durch
  573.  * ramdisk_drive gebenene Laufwerk in _drvbits zu belegen.
  574.  *
  575.  * Rückgabe:
  576.  * 0L: Das gewünschte Laufwerk war schon belegt.
  577.  * 1L: Alles OK.
  578.  */
  579. LONG set_ramdisk_drive(void)
  580. {
  581.     LONG    *_drvbits;
  582.  
  583.     _drvbits = (LONG *)0x4c2;
  584.     if (*_drvbits & (1L << ramdisk_drive))
  585.         return(0L);
  586.     *_drvbits |= (1L << ramdisk_drive);
  587.     return(1L);
  588. }
  589.  
  590. /*
  591.  * increase_refcnts
  592.  *
  593.  * Erhöht den Referenzzähler eines DDs und den "Elternschaftszähler"
  594.  * aller seiner Vorfahren, wenn er bislang noch nicht referenziert
  595.  * wurde.
  596.  *
  597.  * Eingabe:
  598.  * dd: Zeiger auf den zu bearbeitenden RAMDISK_FD
  599.  */
  600. void increase_refcnts(RAMDISK_FD *dd)
  601. {
  602.     dd->fd_refcnt++;
  603.     if (dd->fd_refcnt > 1)
  604.         return;
  605.     for (dd = dd->fd_parent; dd != NULL; dd = dd->fd_parent)
  606.     {
  607.         dd->fd_is_parent++;
  608.         TRACE(("increase_refcnts: is_parent von %L jetzt %L!\r\n", 2,
  609.             dd, (LONG)dd->fd_is_parent));
  610.     }
  611. }
  612.  
  613. /*
  614.  * prepare_dir
  615.  *
  616.  * Initialisiert ein Verzeichnis der Ramdisk. Der Speicher wird
  617.  * mit Nullen gelöscht, anschließend werden die Pseudoeinträge "."
  618.  * und ".." eingerichtet.
  619.  *
  620.  * Eingabe:
  621.  * dir: Zeiger auf das Verzeichnis
  622.  * maxentries: Soviele Einträge soll das Verzeichnis haben
  623.  * parent: Zeiger auf das Elternverzeichnis, oder ROOT_DE, wenn
  624.  *         dir das Wurzelverzeichnis ist.
  625.  */
  626. void prepare_dir(DIRENTRY *dir, WORD maxentries, DIRENTRY *parent)
  627. {
  628.     (kernel->fast_clrmem)(dir, &dir[maxentries]);
  629.     strcpy(dir[0].de_fname, ".");
  630.     dir[0].de_faddr = (char *)dir;
  631.     dir[0].de_nr = 0;
  632.     dir[0].de_maxnr = maxentries;
  633.     dir[0].de_xattr.mode = S_IFDIR | 0777;
  634.     dir[0].de_xattr.index = (LONG)dir;
  635.     dir[0].de_xattr.dev = ramdisk_drive;
  636.     dir[0].de_xattr.rdev = ramdisk_drive;
  637.     dir[0].de_xattr.nlink = 1;
  638.     dir[0].de_xattr.uid = 0;
  639.     dir[0].de_xattr.gid = 0;
  640.     dir[0].de_xattr.size = 0L;
  641.     if (parent != ROOT_DE)
  642.         dir[0].de_xattr.nblocks = 1L;
  643.     else
  644.         dir[0].de_xattr.nblocks = 0L;
  645.     dir[0].de_xattr.mtime = Tgettime();
  646.     dir[0].de_xattr.mdate = Tgetdate();
  647.     dir[0].de_xattr.atime = Tgettime();
  648.     dir[0].de_xattr.adate = Tgetdate();
  649.     dir[0].de_xattr.ctime = Tgettime();
  650.     dir[0].de_xattr.cdate = Tgetdate();
  651.     dir[0].de_xattr.attr = FA_DIR;
  652.     dir[0].de_xattr.reserved2 = 0;
  653.     dir[0].de_xattr.reserved3[0] = 0L;
  654.     dir[0].de_xattr.reserved3[1] = 0L;
  655.     strcpy(dir[1].de_fname, "..");
  656.     if (parent != ROOT_DE)
  657.     {
  658.         parent[0].de_xattr.atime = parent[0].de_xattr.mtime =
  659.             Tgettime();
  660.         parent[0].de_xattr.adate = parent[0].de_xattr.mdate =
  661.             Tgetdate();
  662.         dir[1].de_faddr = (char *)parent;
  663.         dir[1].de_nr = 1;
  664.         dir[1].de_maxnr = 0;
  665.         dir[1].de_xattr = parent[0].de_xattr;
  666.     }
  667.     else
  668.     {
  669.         dir[1].de_faddr = (char *)&root_de;
  670.         dir[1].de_nr = 1;
  671.         dir[1].de_maxnr = 0;
  672.         dir[1].de_xattr.mode = S_IFDIR | 0777;
  673.         dir[1].de_xattr.index = (LONG)parent;
  674.         dir[1].de_xattr.dev = ramdisk_drive;
  675.         dir[1].de_xattr.rdev = ramdisk_drive;
  676.         dir[1].de_xattr.nlink = 1;
  677.         dir[1].de_xattr.uid = 0;
  678.         dir[1].de_xattr.gid = 0;
  679.         dir[1].de_xattr.size = 0L;
  680.         dir[1].de_xattr.nblocks = 1L;
  681.         dir[1].de_xattr.mtime = Tgettime();
  682.         dir[1].de_xattr.mdate = Tgetdate();
  683.         dir[1].de_xattr.atime = Tgettime();
  684.         dir[1].de_xattr.adate = Tgetdate();
  685.         dir[1].de_xattr.ctime = starttime;
  686.         dir[1].de_xattr.cdate = startdate;
  687.         dir[1].de_xattr.attr = FA_DIR;
  688.         dir[1].de_xattr.reserved2 = 0;
  689.         dir[1].de_xattr.reserved3[0] = 0L;
  690.         dir[1].de_xattr.reserved3[1] = 0L;
  691.     }
  692. }
  693.  
  694. /*
  695.  * findfile
  696.  *
  697.  * Funktion zum Suchen einer Datei. Hier muß das Problem angemessen
  698.  * berücksichtigt werden, daß Programme, die in der TOS-Domain
  699.  * laufen, möglicherweise verstümmelte Filenamen liefern, die mit dem
  700.  * tatsächlichen nur noch sehr wenig gemeinsam haben. Besonders
  701.  * unangenehm ist das Ganze mit MagiC 3, da es dort noch kein Pdomain
  702.  * gibt. Es läßt sich daher dort nicht feststellen, ob ein Prozeß
  703.  * lange Dateinamen versteht.
  704.  *
  705.  * Eingabe:
  706.  * dd: Zeiger auf den RAMDISK_FD des Verzeichnisses, in dem gesucht
  707.  *     werden soll.
  708.  * pathname: Name des gesuchten Files/Directories.
  709.  * spos: Nummer des Eintrags, ab dem die Suche beginnen soll (0, wenn
  710.  *       auch "." und ".." gefunden werden dürfen, sonst >= 2).
  711.  * s_or_e: Bestimmt, ob pathname für einen Zugriff gesucht wird
  712.  *         (FF_SEARCH) oder ob für eine Neuanlage des Names geprüft
  713.  *         werden soll, ob er schon existiert (FF_EXIST). Je nach
  714.  *         Modus und aktiver Domain verhält sich die Funktion anders.
  715.  * maybe_dir: Legt fest, ob pathname leer sein darf (ungleich Null)
  716.  *            oder nicht (0). Wenn ja, und pathname ist tatsächlich
  717.  *            leer, wird das aktuelle Verzeichnis selbst gefunden.
  718.  *            Dies ist dann nötig, wenn ein Programm beispielsweise
  719.  *            Fxattr für "c:\gemsys\" aufruft.
  720.  *
  721.  * Rückgabe:
  722.  * Zeiger auf den gefundenen Verzeichniseintrag, oder NULL.
  723.  */
  724. DIRENTRY *findfile(RAMDISK_FD *dd, char *pathname, WORD spos,
  725.     WORD s_or_e, WORD maybe_dir)
  726. {
  727.     WORD        i,
  728.                 max;
  729.     DIRENTRY    *search;
  730.     char        *temp,
  731.                 *dos;
  732.  
  733. /* Sicherheitscheck für den DD */
  734.     if (!is_dir(dd->fd_file->de_xattr.mode))
  735.         return(NULL);
  736. /* Ein leerer Suchname bedeutet u.U. das aktuelle Verzeichnis */
  737.     if (!*pathname && maybe_dir)
  738.         return(dd->fd_file);
  739. /*
  740.  * Das aktuelle Verzeichnis muß überschreitbar sein. Dieser Test
  741.  * erfolgt absichtlich nach der Abfrage auf leeren Suchnamen, da
  742.  * dann ja das Verzeichnis selbst gefunden werden soll, wozu keine
  743.  * Überschreitungsrechte vorhanden sein müssen.
  744.  */
  745.     if (!xaccess(dd->fd_file))
  746.         return(NULL);
  747. /* Zweimal Speicher für temporäre Filenamen anfordern */
  748.     temp = (kernel->int_malloc)();
  749.     dos = (kernel->int_malloc)();
  750.     temp[32] = 0;
  751.     strncpy(temp, pathname, 32L);
  752.     search = (DIRENTRY *)dd->fd_file->de_faddr;
  753.     max = search[0].de_maxnr;
  754. /*
  755.  * Zunächst den Filenamen mit exakten Vergleichen suchen, wenn die
  756.  * MiNT-Domain aktiv ist oder der Directoryeintrag für einen Zugriff
  757.  * ermittelt werden soll
  758.  */
  759.     if ((Pdomain(-1) == EINVFN) || (Pdomain(-1) == 1) ||
  760.         (s_or_e == FF_SEARCH))
  761.     {
  762.         for (i = spos; i < max; i++)
  763.         {
  764.             if (search[i].de_faddr == NULL)
  765.                 continue;
  766.             if (!strcmp(temp, search[i].de_fname))
  767.             {
  768.                 (kernel->int_mfree)(temp);
  769.                 (kernel->int_mfree)(dos);
  770.                 return(&search[i]);
  771.             }
  772.         }
  773.     }
  774. /*
  775.  * Wurde so nichts gefunden, muß NULL geliefert werden, wenn der
  776.  * Prozeß in der MiNT-Domain läuft, oder wenn die Domain nicht
  777.  * ermittelt werden kann _und_ nur auf Existenz geprüft werden soll
  778.  */
  779.     if ((Pdomain(-1) == 1) ||
  780.         ((Pdomain(-1) == EINVFN) && (s_or_e == FF_EXIST)))
  781.     {
  782.         (kernel->int_mfree)(temp);
  783.         (kernel->int_mfree)(dos);
  784.         return(NULL);
  785.     }
  786. /*
  787.  * Sonst den Filenamen in Kleinbuchstaben wandeln und wieder suchen,
  788.  * wenn die TOS-Domain aktiv ist
  789.  */
  790.     if (Pdomain(-1) == 0)
  791.     {
  792.         strlwr(temp);
  793.         for (i = spos; i < max; i++)
  794.         {
  795.             if (search[i].de_faddr == NULL)
  796.                 continue;
  797.             if (!strcmp(temp, search[i].de_fname))
  798.             {
  799.                 (kernel->int_mfree)(temp);
  800.                 (kernel->int_mfree)(dos);
  801.                 return(&search[i]);
  802.             }
  803.         }
  804. /*
  805.  * Wurde immer noch nichts gefunden, ist die Suche erfolglos, wenn
  806.  * nur auf Existenz des Namens geprüft werden soll
  807.  */
  808.         if (s_or_e == FF_EXIST)
  809.         {
  810.             (kernel->int_mfree)(temp);
  811.             (kernel->int_mfree)(dos);
  812.             return(NULL);
  813.         }
  814.     }
  815. /*
  816.  * Jetzt den Suchnamen in's 8+3-Format quetschen und nochmal mit
  817.  * TOS-Gleichheit suchen
  818.  */
  819.     tostrunc(temp, pathname, 0);
  820.     for (i = spos; i < max; i++)
  821.     {
  822.         if (search[i].de_faddr == NULL)
  823.             continue;
  824.         tostrunc(dos, search[i].de_fname, 0);
  825.         TRACE(("findfile: temp = %S, dos = %S\r\n", 2, temp, dos));
  826.         if (!strcmp(temp, dos))
  827.         {
  828.             (kernel->int_mfree)(temp);
  829.             (kernel->int_mfree)(dos);
  830.             return(&search[i]);
  831.         }
  832.     }
  833. /* Es wurde wirklich nichts gefunden */
  834.     (kernel->int_mfree)(temp);
  835.     (kernel->int_mfree)(dos);
  836.     return(NULL);
  837. }
  838.  
  839. /*
  840.  * findfd
  841.  *
  842.  * Sucht einen FD, der entweder frei oder bereits durch einen
  843.  * bestimmten Verzeichniseintrag belegt ist.
  844.  *
  845.  * Eingabe:
  846.  * fname: Zeiger auf Verzeichniseintrag, der im zu suchenden FD
  847.  *        vorhanden sein soll, oder NULL.
  848.  *
  849.  * Rückgabe:
  850.  * Zeiger auf den gefundenen FD, oder NULL.
  851.  */
  852. RAMDISK_FD *findfd(DIRENTRY *fname)
  853. {
  854.     WORD    i;
  855.  
  856. #if 1
  857. /*
  858.  * Ist ein Verzeichniseintrag gegeben, zunächst schauen, ob einer der
  859.  * FDs bereits durch ihn belegt ist. Falls ja, diesen FD liefern.
  860.  */
  861.     if (fname != NULL)
  862.     {
  863.         for (i = 0; i < MAX_FD; i++)
  864.         {
  865.             if (fd[i].fd_file == fname)
  866.                 return(&fd[i]);
  867.         }
  868.     }
  869. #endif
  870. /*
  871.  * War fname gleich NULL oder noch nicht vorhanden, wird jetzt ein
  872.  * freier FD gesucht, gelöscht und zurückgeliefert
  873.  */
  874.     for (i = 0; i < MAX_FD; i++)
  875.     {
  876.         if (fd[i].fd_file == NULL)
  877.         {
  878.             (kernel->fast_clrmem)(&fd[i], &fd[i + 1]);
  879.             return(&fd[i]);
  880.         }
  881.     }
  882. /* Sollte kein FD mehr frei sein, NULL liefern */
  883.     return(NULL);
  884. }
  885.  
  886. /*
  887.  * new_file
  888.  *
  889.  * Erstellt einen neuen Eintrag in einem Verzeichnis an und belegt
  890.  * die wichtigsten Felder vor.
  891.  *
  892.  * Eingabe:
  893.  * curr: Zeiger auf den FD des Verzeichnisses, in dem der neue
  894.  *       Eintrag angelegt werden soll.
  895.  * name: Gewünschter Name des neuen Files.
  896.  *
  897.  * Rückgabe:
  898.  * Zeiger auf den neuen Eintrag, oder NULL.
  899.  */
  900. DIRENTRY *new_file(RAMDISK_FD *curr, char *name)
  901. {
  902.     DIRENTRY    *dir,
  903.                 *new_dir;
  904.     WORD        i,
  905.                 max;
  906.  
  907. /* Ist der Filename unzulässig, NULL zurückliefern */
  908.     if (!check_name(name))
  909.         return(NULL);
  910.     dir = (DIRENTRY *)curr->fd_file->de_faddr;
  911. /*
  912.  * Zum Anlegen eines Eintrags muß das Verzeichnis überschreit- und
  913.  * beschreibbar sein
  914.  */
  915.     if (!waccess(curr->fd_file) || !xaccess(curr->fd_file))
  916.         return(NULL);
  917. /* Einen noch leeren Eintrag suchen */
  918.     max = dir[0].de_maxnr;
  919.     for (i = 2; i < max; i++)
  920.     {
  921.         if (dir[i].de_faddr == NULL)
  922.             break;
  923.     }
  924.     if (i == max)
  925.     {
  926. /*
  927.  * War kein leerer Eintrag mehr vorhanden, muß das Verzeichnis um
  928.  * einen Block erweitert werden. Klappt auch das nicht, liefert die
  929.  * Funktion NULL.
  930.  */
  931.         new_dir = Krealloc(dir,
  932.             dir[0].de_xattr.nblocks * DEFAULTDIR * sizeof(DIRENTRY),
  933.             (dir[0].de_xattr.nblocks + 1L) * DEFAULTDIR *
  934.             sizeof(DIRENTRY));
  935.         if (new_dir == NULL)
  936.             return(NULL);
  937.         dir = new_dir;
  938.         dir[0].de_maxnr += (WORD)DEFAULTDIR;
  939.         dir[0].de_xattr.nblocks++;
  940.         dir[0].de_faddr = (char *)new_dir;
  941.         dir[0].de_xattr.index = (LONG)new_dir;
  942.         curr->fd_file->de_maxnr = dir[0].de_maxnr;
  943.         curr->fd_file->de_xattr.nblocks = dir[0].de_xattr.nblocks;
  944.         curr->fd_file->de_faddr = (char *)new_dir;
  945.         curr->fd_file->de_xattr.index = (LONG)new_dir;
  946.         /*** work_entry für Anpassung von index ***/
  947.     }
  948. /* Den neuen Eintrag komplett löschen und den Namen eintragen */
  949.     (kernel->fast_clrmem)(&dir[i], &dir[i + 1]);
  950.     strncpy(dir[i].de_fname, name, 32L);
  951.     if (Pdomain(-1) == 0)
  952.     {
  953. /*
  954.  * In der TOS-Domain den Namen in Kleinbuchstaben wandeln, weil
  955.  * solche Prozesse oft Filenamen wie STGUIDE.APP liefern, die auf
  956.  * einem casesensitiven Filesystem aber nicht so toll ausehen
  957.  */
  958.         TRACE(("new_file: Wandele Filenamen in Lowercase!\r\n", 0));
  959.         strlwr(dir[i].de_fname);
  960.     }
  961.     else
  962.         TRACE(("new_file: Filename nicht gewandelt!\r\n", 0));
  963. /*
  964.  * Die wichtigsten Felder des Eintrags belegen. Dabei wird das Feld
  965.  * de_faddr bewußt noch nicht gefüllt, der Eintrag bleibt also bis
  966.  * zur Belegung durch die aufrufende Funktion frei.
  967.  */
  968.     dir[i].de_nr = i;
  969.     dir[i].de_xattr.atime = dir[i].de_xattr.mtime =
  970.         dir[i].de_xattr.ctime = Tgettime();
  971.     dir[i].de_xattr.adate = dir[i].de_xattr.mdate =
  972.         dir[i].de_xattr.cdate = Tgetdate();
  973.     dir[i].de_xattr.dev = ramdisk_drive;
  974.     dir[i].de_xattr.rdev = ramdisk_drive;
  975.     dir[i].de_xattr.nlink = 1;
  976.     dir[i].de_xattr.blksize = DEFAULTFILE;
  977.     return(&dir[i]);
  978. }
  979.  
  980. /*
  981.  * dir_is_open
  982.  *
  983.  * Prüft, ob ein gegebenes Verzeichnis per Dopendir geöffnet ist.
  984.  *
  985.  * Eingabe:
  986.  * dir: Zeiger auf den Verzeichniseintrag des Directories.
  987.  *
  988.  * Rückgabe:
  989.  * 0, wenn das Verzeichnis nicht offen ist, 1 sonst.
  990.  */
  991. WORD dir_is_open(DIRENTRY *dir)
  992. {
  993.     WORD    i;
  994.  
  995. /*
  996.  * Alle Directory-Handles durchgehen und prüfen, ob sie das gesuchte
  997.  * Verzeichnis repräsentieren
  998.  */
  999.     for (i = 0; i < MAX_DHD; i++)
  1000.     {
  1001.         if (dhd[i].dhd_dir == dir)
  1002.             return(1);
  1003.     }
  1004.     return(0);
  1005. }
  1006.  
  1007. /*
  1008.  * check_name
  1009.  *
  1010.  * Überprüft einen Filenamen auf Gültigkeit. Erlaubt sind auf der
  1011.  * Ramdisk alle ASCII-Zeichen von 32 bis 127/255 (mit Ausnahme des
  1012.  * Backslash). Die Obergrenze richtet sich dabei nach dem Wert von
  1013.  * eight_bit.
  1014.  *
  1015.  * Eingabe:
  1016.  * name: Zu prüfender Filename.
  1017.  *
  1018.  * Rückgabe:
  1019.  * 0, wenn der Name ungültig ist, 1 sonst.
  1020.  */
  1021. WORD check_name(char *name)
  1022. {
  1023.     WORD    i,
  1024.             max,
  1025.             check;
  1026.  
  1027. /* Leere Namen sind auch nicht zulässig */
  1028.     if (!*name)
  1029.         return(0);
  1030.     max = eight_bit ? 255 : 127;
  1031.     for (i = 0; i < strlen(name); i++)
  1032.     {
  1033.         check = (WORD)name[i] & 0xff;
  1034.         if ((check < 32) || (check > max) ||
  1035.             (name[i] == '\\'))
  1036.         {
  1037.             return(0);
  1038.         }
  1039.     }
  1040.     return(1);
  1041. }
  1042.  
  1043. /*
  1044.  * check_dd
  1045.  *
  1046.  * Prüft einen Directory-Deskriptor auf Gültigkeit. Zwar sollte man
  1047.  * sich darauf verlassen können, daß der Kernel den Funktionen eines
  1048.  * XFS nur korrekte DDs liefert, aber schließtlich ist Vorsicht die
  1049.  * Mutter der Porzellankiste...
  1050.  *
  1051.  * Eingabe:
  1052.  * dd: Zu prüfender DD.
  1053.  *
  1054.  * Rückgabe:
  1055.  * E_OK: DD ist nicht erkennbar falsch.
  1056.  * EDRIVE: DD gehört nicht dem Ramdisk-XFS.
  1057.  * EPTHNF: DD ist in Wirklichkeit ein FD, repräsentiert also kein
  1058.  *         Verzeichnis.
  1059.  */
  1060. LONG check_dd(RAMDISK_FD *dd)
  1061. {
  1062.     if (dd->fd_dmd != ramdisk_dmd)
  1063.         return(EDRIVE);
  1064.     if (!is_dir(dd->fd_file->de_xattr.mode))
  1065.         return(EPTHNF);
  1066.     return(E_OK);
  1067. }
  1068.  
  1069. /*
  1070.  * check_fd
  1071.  *
  1072.  * Wie check_dd, nur für Filedeskriptoren.
  1073.  *
  1074.  * Eingabe:
  1075.  * fd: Zu überprüfender FD.
  1076.  *
  1077.  * Rückgabe:
  1078.  * E_OK: FD ist nicht erkennbar falsch.
  1079.  * EDRIVE: FD gehört nicht dem Ramdisk-XFS.
  1080.  * EFILNF: FD repräsentiert keine Datei.
  1081.  */
  1082. LONG check_fd(RAMDISK_FD *fd)
  1083. {
  1084.     if (fd->fd_dmd != ramdisk_dmd)
  1085.         return(EDRIVE);
  1086.     if (!is_file(fd->fd_file->de_xattr.mode))
  1087.         return(EFILNF);
  1088.     return(E_OK);
  1089. }
  1090.  
  1091. /*
  1092.  * work_entry
  1093.  *
  1094.  * Hilfsfunktion, die für einen bestimmten Directoryeintrag eine
  1095.  * gegebene Aktion durchführt und dabei darauf achtet, daß alle
  1096.  * Repräsentanten dieses Eintrags (also auch die Pseudoeinträge
  1097.  * "." des gleichen und ".." der untergeordneten Verzeichnisse)
  1098.  * mit angepaßt werden. Damit lassen sich alle Funktionen, die sich
  1099.  * auf Verzeichniseinträge beziehen, realisieren, ohne sich um die
  1100.  * genannten Details kümmern zu müssen.
  1101.  *
  1102.  * Eingabe:
  1103.  * dd: Zeiger auf den DD, in dessen Verzeichnis sich der zu ändernde
  1104.  *     Eintrag befindet.
  1105.  * name: Name des Eintrags.
  1106.  * symlink: Zeiger auf Stringzeiger, hier wird ggf. ein Zeiger auf
  1107.  *          das Ziel eines symbolischen Links eingetragen. Ist
  1108.  *          symlink NULL, werden keine symbolischen Links verfolgt.
  1109.  * writeflag: Wenn ungleich Null, wird der Eintrag durch die
  1110.  *            Aktionsfunktion eventuell verändert. Dann, und nur
  1111.  *            dann, werden auch die anderen Repräsentanten
  1112.  *            bearbeitet.
  1113.  * par1: Erster Parameter, den action erhalten soll.
  1114.  * par2: Zweiter Parameter für action.
  1115.  * action: Zeiger auf die Aktionsfunktion, die als Parameter den
  1116.  *         Zeiger auf den zu bearbeitenden Eintrag und par1/par2
  1117.  *         bekommt. Zurückliefern muß die Funktionen einen GEMDOS-
  1118.  *         Returncode. Ist action ein Nullzeiger, muß name ein
  1119.  *         symbolischer Link sein, sonst liefert work_entry sofort
  1120.  *         EINVFN.
  1121.  *
  1122.  * Rückgabe:
  1123.  * GEMDOS-Fehlercode, der meist der Returncode von action ist.
  1124.  */
  1125. LONG work_entry(RAMDISK_FD *dd, char *name, char **symlink,
  1126.     WORD writeflag, LONG par1, LONG par2,
  1127.     LONG (*action)(DIRENTRY *entry, LONG par1, LONG par2))
  1128. {
  1129.     DIRENTRY    *found,
  1130.                 *help;
  1131.     LONG        retcode;
  1132.     WORD        i,
  1133.                 max;
  1134.     XATTR        new;
  1135.  
  1136. /* DD überprüfen */
  1137.     if (check_dd(dd) < 0)
  1138.     {
  1139.         if (action == NULL)
  1140.             return(EINVFN);
  1141.         else
  1142.             return(check_dd(dd));
  1143.     }
  1144. /* Eintrag suchen */
  1145.     if ((found = findfile(dd, name, 0, FF_SEARCH, 1)) == NULL)
  1146.     {
  1147.         if (action == NULL)
  1148.             return(EINVFN);
  1149.         else
  1150.             return(EFILNF);
  1151.     }
  1152. /* Test auf symbolischen Link */
  1153.     if (is_link(found->de_xattr.mode) && (symlink != NULL))
  1154.     {
  1155.         TRACE(("work_entry: Folge symbolischem Link auf %S!\r\n", 1,
  1156.             &found->de_faddr[2]));
  1157.         *symlink = found->de_faddr;
  1158.         return(ELINK);
  1159.     }
  1160.     if (action == NULL)
  1161.         return(EINVFN);
  1162. /*
  1163.  * Sollen Änderungen vorgenommen werden, obwohl sich name nicht auf
  1164.  * das gleiche Verzeichnis bezieht, das auch der DD repräsentiert,
  1165.  * müssen Schreibrechte vorhanden sein
  1166.  */
  1167.     if (writeflag && (dd->fd_file->de_faddr != found->de_faddr) &&
  1168.         !waccess(dd->fd_file))
  1169.     {
  1170.         return(EACCDN);
  1171.     }
  1172. /*
  1173.  * action aufrufen und den Returncode liefern, falls es ein Fehler
  1174.  * war, oder wenn keine Änderungen an Eintrag vorgesehen sind
  1175.  */
  1176.     retcode = (action)(found, par1, par2);
  1177.     if ((retcode < 0L) || !writeflag)
  1178.         return(retcode);
  1179. /*
  1180.  * Ist der Eintrag kein Verzeichnis, gibt es auch keine weiteren
  1181.  * Einträge, die ihn ebenfalls repräsentieren und mitgeändert werden
  1182.  * müßten
  1183.  */
  1184.     if (!is_dir(found->de_xattr.mode))
  1185.         return(retcode);
  1186. /* Sonst den neuen Inhalt des Eintrags zwischenspeichern */
  1187.     new = found->de_xattr;
  1188. /* Den Ursprungseintrag des Verzeichnisses ermitteln */
  1189.     if (!strcmp(found->de_fname, "."))
  1190.         found = dd->fd_file;
  1191.     if (!strcmp(found->de_fname, ".."))
  1192.     {
  1193. /* ".." des Wurzelverzeichnisses hat keine weiteren Repräsentanten */
  1194.         if (dd->fd_parent == NULL)
  1195.             return(retcode);
  1196.         found = dd->fd_parent->fd_file;
  1197.     }
  1198. /*
  1199.  * Jetzt den Inhalt an alle nötigen Positionen kopieren, dabei müssen
  1200.  * auch alle Unterverzeichnisse, soweit vorhanden, berücksichtigt
  1201.  * werden, da hier ".." geändert werden muß.
  1202.  */
  1203.     found->de_xattr = new;
  1204.     found = (DIRENTRY *)found->de_faddr;
  1205.     found->de_xattr = new;
  1206.     max = found->de_maxnr;
  1207.     for (i = 2; i < max; i++)
  1208.     {
  1209.         if ((found[i].de_faddr != NULL) &&
  1210.             is_dir(found[i].de_xattr.mode))
  1211.         {
  1212.             help = (DIRENTRY *)found[i].de_faddr;
  1213.             help[1].de_xattr = new;
  1214.         }
  1215.     }
  1216.     return(retcode);
  1217. }
  1218.  
  1219. /*
  1220.  * set_amtime
  1221.  *
  1222.  * Fungiert als Parameterfunktion für work_entry und setzt die letzte
  1223.  * Zugriffs- bzw. die letzte Änderungszeit auf die aktuellen Werte.
  1224.  *
  1225.  * Eingabe:
  1226.  * entry: Zu bearbeitender Verzeichniseintrag.
  1227.  * set_amtime: Wenn 0, soll die Änderungszeit geändert werden, sonst
  1228.  *             die Zugriffszeit.
  1229.  *
  1230.  * Rückgabe:
  1231.  * Immer E_OK, weil nichts schieflaufen kann.
  1232.  */
  1233. #pragma warn -par
  1234. LONG set_amtime(DIRENTRY *entry, LONG set_atime, LONG unused)
  1235. {
  1236.     if (set_atime)
  1237.     {
  1238.         entry->de_xattr.atime = Tgettime();
  1239.         entry->de_xattr.adate = Tgetdate();
  1240.     }
  1241.     else
  1242.     {
  1243.         entry->de_xattr.mtime = Tgettime();
  1244.         entry->de_xattr.mdate = Tgetdate();
  1245.     }
  1246.     return(E_OK);
  1247. }
  1248. #pragma warn .par
  1249.  
  1250. /*
  1251.  * tostrunc
  1252.  *
  1253.  * Quetscht einen Ramdisk-Filenamen in das 8+3-Format, und zwar nach
  1254.  * folgenden Regeln:
  1255.  * - "." und ".." werden direkt übernommen
  1256.  * - alle unerlaubten Zeichen werden durch "X" ersetzt
  1257.  * - alle Punkte, außer dem letzten, werden durch Kommata ersetzt;
  1258.  *   ist der letzte Punkt auch das letzte Zeichen des Namens, wird
  1259.  *   er gestrichen, ist er das erste Zeichen des Namens, wird er
  1260.  *   doch in ein Komma gewandelt
  1261.  * - alle Zeichen werden in Großbuchstaben gewandelt
  1262.  * - die ersten acht Zeichen vor dem letzten Punkt werden übernommen
  1263.  * - die ersten drei Zeichen nach dem letzten Punkt werden übernommen
  1264.  *   (falls es einen letzten Punkt gibt)
  1265.  *
  1266.  * Beispiele:
  1267.  * Langer Dokumentenanme.txt -> LANGERXD.TXT
  1268.  * name.mit.vielen.punkten -> NAME,MIT.PUN
  1269.  * .profile -> ,PROFILE
  1270.  * punkt.am.ende. -> PUNKT,AM
  1271.  *
  1272.  * Natürlich können so zwei eigentlich verschiedene Dateinamen auf
  1273.  * den selben TOS-Namen abgebildet werden, was mit nicht angepaßten
  1274.  * Programmen durchaus Probleme bereiten kann. Der Aufwand, dieses
  1275.  * Problem absolut sicher zu umgehen, übersteigt allerdings meiner
  1276.  * Meinung nach den möglichen Nutzen.
  1277.  *
  1278.  * Eingabe:
  1279.  * dest: Zeiger auf den Zielnamen, hier wird also das Ergebnis der
  1280.  *       Umwandlung abgelegt.
  1281.  * src: Zeiger auf den Ursprungsnamen.
  1282.  * wildcards: Wenn ungleich Null, werden ? und * im Ursprungsnamen
  1283.  *            übernommen, sonst durch X ersetzt.
  1284.  */
  1285. void tostrunc(char *dest, char *src, WORD wildcards)
  1286. {
  1287.     WORD    i;
  1288.     char    *lastdot,
  1289.             temp[] = "a";
  1290.  
  1291. /* Nur zu Debug-Zwecken */
  1292. #ifdef DEBUG
  1293.     if (!check_name(src))
  1294.     {
  1295.         TRACE(("tostrunc: Falscher Dateiname: %S\r\n", 1, src));
  1296.     }
  1297. #endif
  1298.     TRACE(("tostrunc: %S -> %L\r\n", 2, src, dest));
  1299. /* "." und ".." unverändert kopieren */
  1300.     if (!strcmp(src, ".") || !strcmp(src, ".."))
  1301.     {
  1302.         strcpy(dest, src);
  1303.         return;
  1304.     }
  1305. /*
  1306.  * Den letzten Punkt im Namen suchen. Ist er das erste oder letzte
  1307.  * Zeichen des Namens, wird er "versteckt".
  1308.  */
  1309.     lastdot = strrchr(src, '.');
  1310.     if (lastdot != NULL)
  1311.     {
  1312.         if ((lastdot == src) || !lastdot[1])
  1313.             lastdot = NULL;
  1314.     }
  1315. /*
  1316.  * Den Zielstring vorbereiten und die ersten acht Zeichen vor dem
  1317.  * letzten Punkt einsetzen
  1318.  */
  1319.     strcpy(dest, "");
  1320.     for (i = 0; i < 8; i++)
  1321.     {
  1322.         if (!*src || (src == lastdot))
  1323.             break;
  1324. /* Punkte als Kommas eintragen */
  1325.         if (*src == '.')
  1326.             strcat(dest, ",");
  1327.         else
  1328.         {
  1329. /*
  1330.  * Unerlaubte Zeichen als "X" übernehmen, alle anderen als
  1331.  * Großbuchstaben in den Zielstring einsetzen. "*" und "?" werden
  1332.  * dabei in Abhängigkeit des Parameters wildcard behandelt.
  1333.  */
  1334.             if (strchr("_!@#$%^&()+-=~`;\'\",<>|[]{}", *src) ||
  1335.                 isalnum(*src) || (wildcards && ((*src == '*') ||
  1336.                 (*src == '?'))))
  1337.             {
  1338.                 *temp = toupper(*src);
  1339.                 strcat(dest, temp);
  1340.             }
  1341.             else
  1342.                 strcat(dest, "X");
  1343.         }
  1344.         src++;
  1345.     }
  1346. /*
  1347.  * Gab es einen letzten Punkt, wird er jetzt samt den ersten drei
  1348.  * dahinter folgenden Zeichen (gewandelt wie oben) an den Zielstring
  1349.  * angehängt.
  1350.  */
  1351.     if (lastdot)
  1352.     {
  1353.         strcat(dest, ".");
  1354.         src = lastdot;
  1355.         src++;
  1356.         for (i = 0; i < 3; i++)
  1357.         {
  1358.             if (!*src)
  1359.                 break;
  1360.             if (strchr("_!@#$%^&()+-=~`;\'\",<>|[]{}", *src) ||
  1361.                 isalnum(*src) || (wildcards && ((*src == '*') ||
  1362.                 (*src == '?'))))
  1363.             {
  1364.                 *temp = toupper(*src);
  1365.                 strcat(dest, temp);
  1366.             }
  1367.             else
  1368.                 strcat(dest, "X");
  1369.             src++;
  1370.         }
  1371.     }
  1372. }
  1373.  
  1374. /*
  1375.  * fill_tosname
  1376.  *
  1377.  * Füllt einen von tostrunc gelieferten Namen auf exakt 8+3 Zeichen
  1378.  * auf; tritt dabei im Namen oder in der Extension ein "*" auf, wird
  1379.  * der betroffene Teil des Filenamens ab dieser Position mit "?"
  1380.  * aufgefüllt (für spätere Vergleiche).
  1381.  *
  1382.  * Beispiele:
  1383.  * "PC.PRG" -> "PC      .PRG"
  1384.  * "FOO.C" -> "FOO     .C  "
  1385.  * "AUTO" -> "AUTO    .   "
  1386.  * "*.TXT" -> "????????.TXT"
  1387.  * "ABC*.?X*" -> "ABC?????.?X?"
  1388.  *
  1389.  * Eingabe:
  1390.  * dest: Zeiger auf Zielstring, der mindestens für 13 Zeichen (inkl.
  1391.  *       abschließendem Nullbyte) Platz bieten muß.
  1392.  * src: Zeiger auf zu füllenden String, der dem von tostrunc
  1393.  *      gelieferten Format entsprechen muß.
  1394.  */
  1395. void fill_tosname(char *dest, char *src)
  1396. {
  1397.     WORD    i;
  1398.     char    *dot;
  1399.  
  1400.     TRACE(("fill_tosname...\r\n", 0));
  1401. /* "." und ".." werden direkt behandelt */
  1402.     if (!strcmp(src, "."))
  1403.     {
  1404.         strcpy(dest, ".       .   ");
  1405.         return;
  1406.     }
  1407.     if (!strcmp(src, ".."))
  1408.     {
  1409.         strcpy(dest, "..      .   ");
  1410.         return;
  1411.     }
  1412. /* Ansonsten den Zielstring mit einem leeren Namen belegen */
  1413.     strcpy(dest, "        .   ");
  1414. /*
  1415.  * Alle Zeichen bis zum Punkt werden an den Anfang von dest kopiert
  1416.  */
  1417.     dot = strchr(src, '.');
  1418.     for (i = 0; *src && (src != dot); i++)
  1419.         dest[i] = *src++;
  1420. /*
  1421.  * Alle Zeichen nach dem Punkt (sofern es einen gab) werden hinter
  1422.  * den Punkt des Zielstrings kopiert
  1423.  */
  1424.     if (dot != NULL)
  1425.     {
  1426.         src = ++dot;
  1427.         for (i = 0; *src; i++)
  1428.             dest[9 + i] = *src++;
  1429.     }
  1430. /*
  1431.  * Jetzt noch in beiden Namensteilen nach einem "*" suchen, wird
  1432.  * einer gefunden, wird der Rest des Teilnamens mit "?" gefüllt
  1433.  * (inklusive der Fundposition)
  1434.  */
  1435.     for (i = 0; i < 8; i++)
  1436.     {
  1437.         if (dest[i] == '*')
  1438.         {
  1439.             memset(&dest[i], '?', (LONG)(8 - i));
  1440.             break;
  1441.         }
  1442.     }
  1443.     for (i = 9; i < 12; i++)
  1444.     {
  1445.         if (dest[i] == '*')
  1446.         {
  1447.             memset(&dest[i], '?', (LONG)(12 - i));
  1448.             break;
  1449.         }
  1450.     }
  1451.     TRACE(("fill_tosname liefert: %S\r\n", 1, dest));
  1452. }
  1453.  
  1454. /*
  1455.  * match_tosname
  1456.  *
  1457.  * Vergleicht zwei von fill_tosname gelieferte Namen, wobei einer von
  1458.  * beiden "?" als Wildcards enthalten darf (der andere darf sie auch
  1459.  * enthalten, hier werden sie aber als normale Zeichen angesehen).
  1460.  * Diese Funktion stellt den Maskenvergleich für sfirst/snext dar und
  1461.  * arbeitet zuverlässiger als manche GEMDOS-Version (bei denen laut
  1462.  * Profibuch z.B. "A*.**" auf alle Dateien paßt).
  1463.  *
  1464.  * Eingabe:
  1465.  * to_check: Zu überprüfender Dateiname, im fill_tosname-Format.
  1466.  * sample: Vergleichsname, ebenfalls im fill_tosname-Format, der "?"
  1467.  *         als Wildcards enthalten darf.
  1468.  *
  1469.  * Rückgabe:
  1470.  * 0: to_check und sample sind nicht miteinander vereinbar.
  1471.  * 1: to_check paßt zu sample.
  1472.  */
  1473. WORD match_tosname(char *to_check, char *sample)
  1474. {
  1475.     WORD    i;
  1476.  
  1477.     TRACE(("match_tosname: %S, %S\r\n", 2, to_check, sample));
  1478. /*
  1479.  * Es werden einfach der Reihe nach alle Zeichen der Namen verglichen
  1480.  * (hier wird der Vorteil des von fill_tosname erzeugten Formats
  1481.  * deutlich). Ist an der aktuellen Stelle in sample ein "?" zu
  1482.  * finden, wird nicht verglichen, womit die Wildcardfunktion einfach
  1483.  * erfüllt ist. Beim ersten fehlgeschlagenen Vergleich wird die
  1484.  * Funktion vorzeitig verlassen.
  1485.  */
  1486.     for (i = 0; i < 12; i++)
  1487.     {
  1488.         if (sample[i] != '?')
  1489.             if (sample[i] != to_check[i])
  1490.             {
  1491.                 TRACE(("Warnix\r\n", 0));
  1492.                 return(0);
  1493.             }
  1494.     }
  1495.     TRACE(("Alles klar, paßt\r\n", 0));
  1496.     return(1);
  1497. }
  1498.  
  1499. /*
  1500.  * xext enthält die Filenamensendungen (verkehrt herum), bei denen
  1501.  * beim Anlegen in der TOS-Domain automatisch das x-Flag für
  1502.  * "Ausführbar" gesetzt wird
  1503.  */
  1504. static char    *xext[] = {"sot.", "ptt.", "grp.", "ppa.", "ptg.",
  1505.     "cca."};
  1506.  
  1507. /*
  1508.  * has_xext
  1509.  *
  1510.  * Diese Funktion prüft, ob ein Filename eine Extension hat, die
  1511.  * normalerweise ein ausführbares Programm kennzeichnet. Dieser Test
  1512.  * schlägt immer fehl, wenn gerade die MiNT-Domain aktiv ist, weil
  1513.  * solche Programme die Flags für "ausführbar" selbst setzen sollten.
  1514.  * Die Vergleichsnamen sind oben im Array xext festgelegt.
  1515.  *
  1516.  * Eingabe:
  1517.  * name: Zeiger auf zu überprüfenden Filenamen.
  1518.  *
  1519.  * Rückgabe:
  1520.  * 0: name hat keine passende Extension bzw. die MiNT-Domain ist
  1521.  *    aktiv
  1522.  * 1: Die TOS-Domain ist aktiv und name hat eine passende Endung.
  1523.  */
  1524. WORD has_xext(char *name)
  1525. {
  1526.     char    *temp;
  1527.     WORD    i;
  1528.  
  1529.     if (Pdomain(-1) == 1)
  1530.         return(0);
  1531.     temp = (kernel->int_malloc)();
  1532.     temp[32] = 0;
  1533.     strncpy(temp, name, 32L);
  1534.     strrev(temp);
  1535.     for (i = 0; i < (sizeof(xext) / sizeof(char *)); i++)
  1536.     {
  1537.         if (!strnicmp(temp, xext[i], strlen(xext[i])))
  1538.         {
  1539.             (kernel->int_mfree)(temp);
  1540.             return(1);
  1541.         }
  1542.     }
  1543.     (kernel->int_mfree)(temp);
  1544.     return(0);
  1545. }
  1546.  
  1547. /*
  1548.  * Kmalloc
  1549.  *
  1550.  * Funktion, die dauerhaften Speicher anfordert, der also nur durch
  1551.  * ein explizites Kfree (nur ein Makro für Mfree) wieder freigegeben
  1552.  * wird. Gäbe es diese Möglichkeit in MagiC nicht, wäre ein XFS wie
  1553.  * dieses nutzlos, weil bei einem Programmende der Teil der Daten,
  1554.  * der von diesem Programm angelegt wurde, wieder verschwinden würde.
  1555.  * Der Name ist nicht nur zufällig an den der Funktion aus der MiNT-
  1556.  * Kernelstruktur angelehnt...
  1557.  * Die Funktion achtet außerdem darauf, daß der größte freie
  1558.  * Speicherblock die in leave_free festgelegte Mindestgröße nicht
  1559.  * unterschreitet und fordert immer den durch ram_type festgelegten
  1560.  * Speichertyp an.
  1561.  *
  1562.  * Eingabe:
  1563.  * len: Wieviele Bytes sollen belegt werden, bei -1L wird die Länge
  1564.  *      des größten zusammenhängenden Speicherblocks abzüglich der
  1565.  *      freizuhaltenden Bytes geliefert (ggf. 0L).
  1566.  *
  1567.  * Rückgabe:
  1568.  * Zeiger auf den allozierten Speicherblock, oder NULL.
  1569.  */
  1570. void *Kmalloc(LONG len)
  1571. {
  1572.     LONG    free,
  1573.             new_free;
  1574.     void    *block;
  1575.  
  1576. /* Länge des größen verfügbaren Speicherblocks ermitteln */
  1577.     free = (LONG)Mxalloc(-1L, ram_type);
  1578.     if (len == -1)
  1579.     {
  1580. /*
  1581.  * Soll die Zahl der für die Ramdisk noch freien Bytes geliefert
  1582.  * werden, muß von der gerade ermittelten Zahl noch die Anzahl der
  1583.  * mindestens freizuhaltenden Bytes abgezogen werden. Ggf. ist das
  1584.  * Ergebnis Null.
  1585.  */
  1586.         if (free < leave_free)
  1587.             return(0L);
  1588.         return((void *)(free - leave_free));
  1589.     }
  1590. /*
  1591.  * Versuchen, einen Block der gewünschten Größe anzufordern; klappt
  1592.  * das nicht, muß NULL geliefert werden
  1593.  */
  1594.     if ((block = Mxalloc(len, 0x4000 | ram_type)) == NULL)
  1595.         return(NULL);
  1596. /*
  1597.  * Sonst prüfen, ob sich die Länge des größten verfügbaren
  1598.  * Speicherblock geändert hat. Falls nicht, kann der Block so als
  1599.  * Ergebnis geliefert werden. Dabei wird absichtlich nicht geprüft,
  1600.  * ob der größte verfügbare Block noch groß genug ist, da seine Länge
  1601.  * durch unser Mxalloc ohnehin nicht beeinflußt wurde.
  1602.  */
  1603.     new_free = (LONG)Mxalloc(-1L, ram_type);
  1604.     if (new_free == free)
  1605.         return(block);
  1606. /*
  1607.  * Hat sich die Größe jedoch verändert, muß der neue Wert noch groß
  1608.  * genug sein. Falls nicht, wird der Block wieder freigegeben und
  1609.  * NULL geliefert.
  1610.  */
  1611.     if (new_free < leave_free)
  1612.     {
  1613.         Mfree(block);
  1614.         return(NULL);
  1615.     }
  1616. /* Ansonsten ist alles OK, der Block ist damit das Ergebnis */
  1617.     return(block);
  1618. }
  1619.  
  1620. /*
  1621.  * Krealloc
  1622.  *
  1623.  * Funktion, um einen Speicherblock auf eine neue Größe zu bringen.
  1624.  * Dabei bleibt der alte Inhalt intakt (natürlich nur bis zum
  1625.  * Minimum aus alter und neuer Länge).
  1626.  *
  1627.  * Eingabe:
  1628.  * ptr: Bisheriger Zeiger auf den Speicherblock.
  1629.  * old_len: Alte Länge des Blocks.
  1630.  * new_len: Neue Länge des Blocks.
  1631.  *
  1632.  * Rückgabe:
  1633.  * Entweder Zeiger auf neuen Speicherblock in gewünschter Größe, oder
  1634.  * NULL. In letzterem Fall ist der alte Pointer weiterhin gültig,
  1635.  * der Inhalt unverändert.
  1636.  */
  1637. void *Krealloc(void *ptr, LONG old_len, LONG new_len)
  1638. {
  1639.     char *new_ptr;
  1640.  
  1641. /*
  1642.  * Versuchen, einen Speicherblock der neuen Größe anzufordern;
  1643.  * notfalls gleich NULL liefern
  1644.  */
  1645.     if ((new_ptr = Kmalloc(new_len)) == NULL)
  1646.         return(NULL);
  1647. /*
  1648.  * Alle Bytes des alten Blocks, die in den neuen Block passen,
  1649.  * dorthin kopieren
  1650.  */
  1651.     memcpy(new_ptr, ptr, (old_len < new_len) ? old_len : new_len);
  1652. /* Bei Bedarf den noch freien Bereich des neuen Blocks löschen */
  1653.     if (new_len > old_len)
  1654.     {
  1655.         (kernel->fast_clrmem)(&new_ptr[old_len],
  1656.             &new_ptr[new_len - 1L]);
  1657.     }
  1658. /* Alten Pointer freigeben */
  1659.     Kfree(ptr);
  1660.     return(new_ptr);
  1661. }
  1662.  
  1663. #ifdef DEBUG
  1664.  
  1665. #undef O_RDWR
  1666. #undef O_APPEND
  1667. #undef O_CREAT
  1668. #define O_RDWR        0x02
  1669. #define O_APPEND    0x08
  1670. #define O_CREAT        0x200
  1671.  
  1672. /*
  1673.  * trace
  1674.  *
  1675.  * Hilfsfunktion für Debuggingzwecke, die über die Kernelfunktion
  1676.  * _sprintf einen Ausgabestring erzeugt und diesen dann in das
  1677.  * Logfile schreibt.
  1678.  *
  1679.  * Eingabe:
  1680.  * format: Formatstring, wie in der MagiC-Doku beschrieben.
  1681.  * params: Anzahl der Parameter, die noch folgen.
  1682.  * ...: Die Parameter für den Formatstring, soweit nötig.
  1683.  */
  1684. void trace(char *format, WORD params, ...)
  1685. {
  1686.     va_list        args;
  1687.     static char    output[128];
  1688.     static LONG    out[10];
  1689.     WORD        i,
  1690.                 handle;
  1691.     LONG        err;
  1692.  
  1693.     va_start(args, params);
  1694.     params = (params > 10) ? 10 : params;
  1695.     for (i = 0; i < params; i++)
  1696.         out[i] = va_arg(args, LONG);
  1697.     va_end(args);
  1698.     (kernel->_sprintf)(output, format, out);
  1699.     if (debug_to_screen)
  1700.         Cconws(output);
  1701.     else
  1702.     {
  1703.         if ((err = Fopen(logfile, O_RDWR|O_APPEND|O_CREAT)) >= 0L)
  1704.         {
  1705.             handle = (WORD)err;
  1706.             Fwrite(handle, strlen(output), output);
  1707.             Fclose(handle);
  1708.         }
  1709.         else
  1710.             Cconws(output);
  1711.     }
  1712. }
  1713. #endif /* DEBUG */
  1714.  
  1715. /*
  1716.  * get_cookie
  1717.  *
  1718.  * Prüft, ob ein bestimmter Cookie vorhanden ist
  1719.  * und liefert, wenn gewünscht, dessen Wert.
  1720.  *
  1721.  * Eingabe:
  1722.  * cookie: Zu suchender Cookie (z.B. 'MiNT')
  1723.  * value: Zeiger auf einen vorzeichenlosen Long,
  1724.  *        in den der Wert des Cookies geschrieben
  1725.  *        werden soll. Ist dies nicht gewünscht/
  1726.  *        erforderlich, einen Nullzeiger über-
  1727.  *        geben.
  1728.  *
  1729.  * Rückgabe:
  1730.  * 0: Cookie nicht vorhanden, value unbeeinflußt
  1731.  * 1: Cookie vorhanden, Wert steht in value (wenn
  1732.  *    value kein Nullpointer ist)
  1733.  */
  1734. WORD get_cookie(ULONG cookie, ULONG *value)
  1735. {
  1736.     LONG    *jar,
  1737.             old_stack;
  1738.     
  1739.     /*
  1740.      * Den Zeiger auf den Cookie-Jar ermitteln,
  1741.      * dabei ggf. in den Supervisor-Modus
  1742.      * wechseln.
  1743.      */
  1744.     if (Super((void *)1L) == 0L)
  1745.     {
  1746.         old_stack = Super(0L);
  1747.         jar = *((LONG **)0x5a0L);
  1748.         Super((void *)old_stack);
  1749.     }
  1750.     else
  1751.         jar = *(LONG **)0x5a0;
  1752.     
  1753.     /*
  1754.      * Ist die "Keksdose" leer, gleich Null zu-
  1755.      * rückliefern, da ja gar kein Cookie
  1756.      * vorhanden ist.
  1757.      */
  1758.     if (jar == 0L)
  1759.         return(0);
  1760.     
  1761.     /*
  1762.      * Sonst den Cookie-Jar bis zum Ende durch-
  1763.      * suchen und im Erfolgsfall 1 zurückliefern.
  1764.      * Falls value kein Nullpointer war, vorher
  1765.      * den Wert des Cookies dort eintragen.
  1766.      */
  1767.     while (jar[0])
  1768.     {
  1769.         if (jar[0] == cookie)
  1770.         {
  1771.             if (value != 0L)
  1772.                 *value = jar[1];
  1773.             
  1774.             return(1);
  1775.         }
  1776.         
  1777.         jar += 2;
  1778.     }
  1779.     /*
  1780.      * Bis zum Ende gesucht und nichts gefunden,
  1781.      * also 0 zurückgeben.
  1782.      */
  1783.     return(0);
  1784. }
  1785.  
  1786. /* EOF */
  1787.